// backend/server.js

const express = require('express');
const cors = require('cors');
const neo4j = require('neo4j-driver');
const axios = require('axios');

const app = express();
const port = 3000;

// --- 配置 ---
// 警告: 在生产环境中，绝不应将密码硬编码。请使用环境变量。
const NEO4J_URI = 'bolt://10.14.126.45:7687/';
const NEO4J_USER = 'neo4j';
const NEO4J_PASSWORD = '11223344';
const NEO4J_DATABASE = 'neo4j';
const QA_API_URL = 'http://10.14.120.217:1234/api/ask';

// --- 中间件 ---
app.use(cors()); // 允许所有跨域请求
app.use(express.json()); // 解析JSON请求体

// --- Neo4j 驱动实例 ---
const driver = neo4j.driver(NEO4J_URI, neo4j.auth.basic(NEO4J_USER, NEO4J_PASSWORD));

// --- 辅助函数：将 Neo4j 响应转换为 G6 格式 ---
// 这是关键的一步，因为 Neo4j 的返回格式和 G6 需要的格式不同
function transformToG6(records) {
    const nodes = new Map();
    const edges = new Map();

    records.forEach(record => {
        // record.forEach 是为了处理查询返回的多个列 (a, r, b)
        record.forEach(value => {
            if (value && value.identity) { // 检查是否是节点或关系
                if (value.labels) { // 是节点
                    const id = value.identity.toString();
                    if (!nodes.has(id)) {
                        nodes.set(id, {
                            id: id,
                            label: value.properties.name || value.labels[0] || 'Node', // 优先用name属性
                            ...value.properties, // 将所有属性都带上
                            // G6样式可以基于label进行定义
                            style: {
                                fill: getNodeColor(value.labels[0]),
                            },
                            _labels: value.labels // 保存原始标签
                        });
                    }
                } else if (value.type) { // 是关系
                    const id = value.identity.toString();
                    if (!edges.has(id)) {
                        edges.set(id, {
                            id: id,
                            source: value.start.toString(),
                            target: value.end.toString(),
                            label: value.type,
                            ...value.properties
                        });
                    }
                }
            }
        });
    });

    return { nodes: Array.from(nodes.values()), edges: Array.from(edges.values()) };
}

// 辅助函数：根据节点标签分配颜色
function getNodeColor(label) {
    switch (label) {
        case 'DiseaseName': return '#F08080'; // 红色系
        case 'DiseaseClass': return '#20B2AA'; // 绿色系
        case 'QualitativeDes': return '#87CEEB'; // 蓝色系
        case 'QuantitativeDes': return '#FFA07A'; // 橙色系
        default: return '#D3D3D3'; // 默认灰色
    }
}


// --- API 路由 ---

// 路由1：展开节点
app.post('/api/expand-node', async (req, res) => {
    const { nodeId } = req.body;
    if (!nodeId) {
        return res.status(400).send({ error: 'nodeId is required' });
    }

    const session = driver.session({ database: NEO4J_DATABASE });
    try {
        // 使用 id() 函数查询，nodeId 必须是整数
        const result = await session.run(
            'MATCH (a)-[r]-(b) WHERE id(a) = toInteger($nodeId) RETURN a, r, b',
            { nodeId: nodeId }
        );
        const g6Data = transformToG6(result.records);
        res.json(g6Data);
    } catch (error) {
        console.error('Neo4j query error:', error);
        res.status(500).send({ error: 'Failed to query Neo4j' });
    } finally {
        await session.close();
    }
});

// 路由2：代理问答API
app.post('/api/ask', async (req, res) => {
    try {
        const response = await axios.post(QA_API_URL, req.body, {
            headers: { 'Content-Type': 'application/json' }
        });
        // 直接将QA API的响应转发给前端
        res.json(response.data);
    } catch (error) {
        console.error('QA API request error:', error.message);
        res.status(500).send({ error: 'Failed to request QA API' });
    }
});

// 路由3：获取初始图谱数据 (例如，显示前20个病害及其关系)
app.get('/api/initial-graph', async (req, res) => {
    const session = driver.session({ database: NEO4J_DATABASE });
    try {
        // 一个示例查询，可以按需修改
        const result = await session.run(
            'MATCH (n:DiseaseName)-[r]-(m) WITH n,r,m LIMIT 20 RETURN n,r,m'
        );
        const g6Data = transformToG6(result.records);
        res.json(g6Data);
    } catch (error) {
        console.error('Initial graph query error:', error);
        res.status(500).send({ error: 'Failed to fetch initial graph' });
    } finally {
        await session.close();
    }
});


app.listen(port, () => {
    console.log(`Backend server listening at http://localhost:${port}`);
});